package com.cfpl.admin_service.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cfpl.admin_service.DTO.LoginFormDTO;
import com.cfpl.admin_service.VO.AdminLoginVO;
import com.cfpl.admin_service.VO.LoginAdmin;
import com.cfpl.admin_service.mapper.AdminMapper;
import com.cfpl.admin_service.mapper.RoleMapper;
import com.cfpl.admin_service.service.AdminService;
import com.cfpl.project_common.constant.AdminConstant;
import com.cfpl.project_common.constant.RedisConstants;
import com.cfpl.project_common.enums.CodeEnum;
import com.cfpl.project_common.exception.BusException;
import com.cfpl.project_common.pojo.Admin;
import com.cfpl.project_common.pojo.Permission;
import com.cfpl.project_common.pojo.Role;
import com.cfpl.project_common.util.JWTUtil;
import com.cfpl.project_common.util.Md5Util;
import com.cfpl.project_common.util.RegexPatterns;
import com.cfpl.project_common.util.RegexUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
* @author 14720
* 2023-10-10 11:09:05
*/
@Service
@Slf4j
public class AdminServiceImpl implements AdminService {

    @Lazy
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    @Autowired
    private AuthenticationManager authenticationManager;        //这个东西就是起到认证登录信息的作用
    @Autowired
    private AdminMapper adminMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 添加管理员
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertAdmin(Admin admin) {
        //校验 手机号，邮箱
        if (!RegexUtils.isEmailValid(admin.getAdminEmail())){
            throw new BusException(CodeEnum.REGISTER_EMAIL_FORMAT_ERROR);
        }
        if (!RegexUtils.isPhoneValid(admin.getAdminPhone())){
            throw new BusException(CodeEnum.REGISTER_PHONE_FORMAT_ERROR);
        }
//        管理员添加初始密码，默认123456
//        if (!RegexUtils.isPasswordValid(admin.getAdminPassword())){
//            throw new BusException(CodeEnum.REGISTER_PASSWORD_FORMAT_ERROR);
//        }

        //security框架加密
        String cipher = bCryptPasswordEncoder.encode(admin.getAdminPassword());
        admin.setAdminPassword(cipher);
        //入职时间
        admin.setCreateTime(new Date());
        //开启状态
        admin.setDelete(AdminConstant.ADMIN_STATUS_ALIVE);
        adminMapper.insert(admin);
//获取角色集合   添加的时候可以选角色 也可以不选角色
        if (admin.getRoleList() == null){
            return;
        }
        List<Role> roleList = admin.getRoleList();
        Long[] roleIds = new Long[roleList.size()];
        for (int i = 0; i < roleList.size(); i++) {
            roleIds[i] = roleList.get(i).getRoleId();
        }
        adminMapper.assignAdminRoles(admin.getAdminId(), roleIds);
    }

    /**
     * 更改管理员状态
     */
    @Override
    @Transactional
    public void adminSwitch(Long adminId) {
        Admin admin = adminMapper.selectById(adminId);
        admin.setDelete(!admin.isDelete());
        adminMapper.updateStatus(admin);
    }

    /**
     * 修改管理员信息
     */
    @Override
    @Transactional
    public void updateAdmin(Admin admin) {
        //当前对象的密码为空->原密码
        if (StrUtil.isNotBlank(admin.getAdminPassword())){
            //校验密码是否为空 是否符合要求
            if (admin.getAdminPassword().matches(RegexPatterns.PASSWORD_REGEX)){
                admin.setAdminPassword(bCryptPasswordEncoder.encode(admin.getAdminPassword()));
            }else {
                throw new BusException(CodeEnum.REGISTER_PASSWORD_FORMAT_ERROR);
            }
        }else {
            admin.setAdminPassword(null);
        }

        adminMapper.updateAdminInfo(admin);

    }


    /**
     * @param queryCondition 手机号，邮箱 精准匹配
     */
    @Override
    public Admin loginQueryAdmin(String queryCondition) {
        if (StrUtil.isBlank(queryCondition)){
            throw new BusException(CodeEnum.PARAMETER_ERROR);
        }
        LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(Admin::getAdminPhone,queryCondition)
                .or()
                .eq(Admin::getAdminEmail,queryCondition);
        return adminMapper.selectOne(queryWrapper);
    }

    /**
     * 分页查询
     * @param currentPage 当前页
     * @param pageSize  每页条数
     *   查询管理员  姓名，手机号，邮箱，
     * @return 分页对象
     */
    @Override
    public Page<Admin> queryPage(int currentPage, int pageSize,String condition) {

        LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
        if (condition != null){
            queryWrapper.eq(Admin::getAdminPhone,condition).or()
                    .eq(Admin::getAdminEmail,condition).or()
                    .like(Admin::getAdminName,condition);
        }

        return adminMapper.selectPage(new Page<>(currentPage, pageSize), queryWrapper);
    }

    /**
     * 根据ID查询管理员
     * @param adminId id
     * @return
     */
    @Override
    public Admin queryAdminById(Long adminId) {
        return adminMapper.queryAdminDetailInfo(adminId);
    }

    /**
     * 给管理员分配(修改)角色信息
     * @param adminId 管理员编号
     * @param roleIds 角色编号
     */
    @Override
    @Transactional
    public void assignAdminRoles(Long adminId, Long[] roleIds) {
        if (adminId == null){
            throw new BusException(CodeEnum.PARAMETER_ERROR);
        }
        if (roleIds == null || roleIds.length < 1){
            throw new BusException(CodeEnum.PARAMETER_ERROR);
        }

        //删除角色信息
        adminMapper.deleteAdminRolesInfo(adminId);
        //添加角色信息
        adminMapper.assignAdminRoles(adminId, roleIds);
    }

    /**
     * 查询对应权限
     * @param aid 管理员编号
     * @return list
     */
    @Override
    public List<Permission> queryAllPermissionByUserName(Long aid) {
        return adminMapper.queryAllPermissionByUserName(aid);
    }



    /**
     * 验证管理员
     * @param loginFormDTO 管理员登录信息
     * @return AdminLoginVO
     */
    @Override
    public AdminLoginVO verifyAdminInfo(LoginFormDTO loginFormDTO) {
        log.info("************进入AdminServiceImpl************");
        //authenticationToken 携带登录参数  参数1 账号   参数2 密码
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginFormDTO.getAccount(),loginFormDTO.getPassword());

        //UsernamePasswordAuthenticationToken 实现了 authentication接口
        Authentication authentication = authenticationManager.authenticate(authenticationToken);
        //账号密码错误在MyAuthenticationEntryPoint处理了
//        if (Objects.isNull(authentication)) {
//            throw new BusException(CodeEnum.USERNAME_OR_PASSWORD_ERROR);
//        }
        //getPrincipal 获取出来的对象就是LoginAdmin  因为UserDetailService返回的的就是LoginAdmin
        LoginAdmin loginAdmin = (LoginAdmin) authentication.getPrincipal();
        Admin admin = loginAdmin.getAdmin();
        List<Role> roleList = roleMapper.queryRolesInfoByAdminId(admin.getAdminId());

        //判断状态
        if (!admin.isDelete()){
            throw new BusException(CodeEnum.USER_STATUS_ERROR);
        }

        //生成Token
        String token = JWTUtil.sign(admin);
        //登录用户存入Redis中    只要token过期或者退出登录后再次登录，存入Redis的权限信息一定是最新的
        stringRedisTemplate.opsForValue()
                .set(RedisConstants.LOGIN_ADMIN + token,
                        JSONUtil.toJsonStr(loginAdmin),
                        RedisConstants.EXPIRE_TIME_SECONDS,
                        TimeUnit.SECONDS);
        return new AdminLoginVO(
                admin.getAdminId(),
                admin.getAdminName(),
                admin.getAdminHeadpic(),
                token,
                loginAdmin.getPermissionList(),
                roleList
        );
    }

    @Override
    public void logOut(HttpServletRequest request) {
        String token = request.getHeader("token");
//        UsernamePasswordAuthenticationToken authenticationToken = (UsernamePasswordAuthenticationToken)SecurityContextHolder.getContext().getAuthentication();
//        LoginAdmin loginAdmin  = (LoginAdmin) authenticationToken.getPrincipal();
        //删除当前用户的缓存信息
        stringRedisTemplate.delete(RedisConstants.LOGIN_ADMIN + token);

    }

    @Override
    public boolean checkPathExisted(File file) {
        if (!(file.exists() && file.isDirectory())){
            //创建用户头像目录
            try {
                file.mkdirs();
            } catch (Exception e) {
                throw new BusException(CodeEnum.SYSTEM_ERROR);
            }
        }
        return true;
    }

    @Override
    public void updateAdminHeadPic(String filename,Long adminID) {
        adminMapper.updateAdminHeadPic(filename,adminID);
    }


}




